<?php
// Engine support functions

include_once($_SERVER['DOCUMENT_ROOT'] . "/config.php");

include_once(ABS_PATH . "misc/functions.php");

if (!function_exists("_log"))
	echo "Error: couldn't find _log()<br />\n";

define('NULL_KEY', "00000000-0000-0000-0000-000000000000");
define('OS_NPC_SIT_NOW', 0);

// for genetic algorithm
define('RADIUS', 10); // this is the size of the grid that is thrown around the avatar
define('POPULATION_SIZE', 50); // was 50
define('GENERATIONS', 20); // was 20 for 20x20 grid
define('CHROMOSOMES', 7); // was 28 for 20x20 grid
define('CROSSOVER_RATE', 90); // = 90%, we use a random number generator for 0-100
define('MUTATION_RATE', 5);   // = 0.005%, we use a random number generator for 0-1000 - experimentar 0.01
define('WALKING_SPEED', 3.19); // avatar walking speed in meters per second

// Weights for Shi & Cui
define('W1', 1.0); // Sub-function of Path Length
define('W2', 10.0); // Sub-function of Path Security
define('W3', 5.0); // Sub-function of Smoothness

// Calculates distance between two vectors
function distance($vec1, $vec2)
{
	if (!is_array($vec1) || !is_array($vec2))
		return null;

	return sqrt( pow($vec2[0] - $vec1[0], 2)
		+ pow($vec2[1] - $vec1[1], 2)
		+ pow($vec2[2] - $vec1[2], 2));
}

function callURL($URL, $encodedRequest)
{
	$output = "";

	_log(__FILE__ . ":" . __LINE__ . " URL call: " . $URL . " Data: " . $encodedRequest);

	try {
		// create curl resource
		$ch = curl_init();

		// set url
		curl_setopt($ch, CURLOPT_URL, $URL);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedRequest);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_POST, 1);

		//return the transfer as a string
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 60);

		// $output contains the output string
		$output = curl_exec($ch);

		// close curl resource to free up system resources
		curl_close($ch);
	}
	catch (Exception $e)
	{
		echo $e->getCode() . ": " . $e->getMessage() . "<br />";
		echo "cURL error: " . curl_error($ch) . "<br />";
		_log(__FILE__ . ":" . __LINE__ . "cURL error: " . curl_error($ch));
		return null;
	}

	// echo "cURL call returned: -->" . $output . " <--<br />";
	return $output;
}

// auxiliary functions which might get dropped

// given an obstacle value, return a class for visually showing its 'danger zone'
// Note that "obstacle" doesn't show distance but rather a lot of nearby objects
//  values are arbitrary. Note that we limit obstacle calculations around RADIUS
function classObstacle($obs)
{
	if ($obs == 0.0)
	{
		return "";
	}
	elseif ($obs < 5.0)
	{
		return " class='obstacle-few'";
	}
	elseif ($obs < 20.0)
	{
		return " class='obstacle-medium'";
	}
	else
	{
		return " class='obstacle-many'";
	}
}

// Display a table for population
function showPopulation($pop, $popSize, $popChromosomes)
{
	if (!is_array($pop))
	{
		echo "Not an array.<br />\n";
		return;
	}
	if (empty($pop))
	{
		echo "Array is empty!<br />\n";
		return;
	}

	echo "<table class='narrow'>\n\t<thead><tr><th>#</th><th>1/Fit</th><th>CurPos</th>";

	for ($y = 1; $y < (CHROMOSOMES - 1); $y++)
	{
		echo "<th>" . $y . "</th>";
	}
	echo "<th>Target</th></tr></thead>\n\t<tbody>";

	for ($i = 0; $i < POPULATION_SIZE; $i++)
	{
		printf("<tr><td>%02d</td><td class='fitness'>%03.3f</td>", $i, $pop[$i]["fitness"]);

		for ($y = 0; $y < CHROMOSOMES; $y++)
		{
			echo "<td" . classObstacle($pop[$i][$y]["obstacle"]) . ">" . $pop[$i][$y]["x"] . "," . $pop[$i][$y]["y"] . "," . $pop[$i][$y]["z"] . "</td>";
		}
		echo "</tr>\n";
		// print distances to destination
		echo "<tr><td></td><td></td>";
		for ($y = 0; $y < CHROMOSOMES; $y++)
		{
			printf("<td>d:%03.3f</td>", $pop[$i][$y]["distance"]);
		}
		echo "</tr>\n";
		// print obstacle calculations
		echo "<tr><td></td><td></td>";
		for ($y = 0; $y < CHROMOSOMES; $y++)
		{
			printf("<td%s>o:%03.3f</td>", classObstacle($pop[$i][$y]["obstacle"]), $pop[$i][$y]["obstacle"]);
		}
		echo "</tr>\n";
		// print obstacle calculations
		echo "<tr><td></td><td></td>";
		for ($y = 0; $y < CHROMOSOMES; $y++)
		{
			printf("<td>θ:%03.3f</td>", $pop[$i][$y]["angle"]);
		}
		echo "</tr>\n";
	}

	echo "</tbody>\n\t<tfoot><tr><th>#</th><th>1/Fit</th><th>CurPos</th>";

	for ($y = 1; $y < (CHROMOSOMES - 1); $y++)
	{
		echo "<th>" . $y . "</th>";
	}
	echo "<th>Target</th></tr></tfoot>\n</table>\n";

}

// Auxiliary function for automatic sorting by fitness
//  this takes two parameters, assumes they are special arrays, and compares the fitness
function cmp($a, $b)
{
	if ($a["fitness"] == $b["fitness"])
		return 0;

	return ($a["fitness"] < $b["fitness"]) ? -1 : 1;
}

// Auxiliary function for sorting points along a line
//  Test 1: This uses Ruhe's algorithm, see http://stackoverflow.com/a/20399468/1035977
//  Test 2: just compare angles of x,y

function point_cmp($a, $b)
{
	global $centerPoint;

	/* Attempt #1: Ruhe's algorithm

	$theta_a = atan2($a["y"] - $centerPoint["y"], $a["x"] - $centerPoint["x"]);
    $angle_a = fmod(M_PI - M_PI_4 + $theta_a, 2 * M_PI);

	$theta_b = atan2($b["y"] - $centerPoint["y"], $b["x"] - $centerPoint["x"]);
    $angle_b = fmod(M_PI - M_PI_4 + $theta_a, 2 * M_PI);

	if ($angle_a == $angle_b)
		return 0;

	return ($angle_a < $angle_b) ? -1 : 1;
*/

	/*
	// Attempt #2: just angles

	if ($a["angle"] == $b["angle"])
		return 0;

	return (abs($a["angle"]) < abs($b["angle"])) ? -1 : 1;
*/
	// Attempt #3: Just compare x,y! This is a terrible solution but better than nothing
	// using algorithm from Anonymous on http://www.php.net/manual/en/function.usort.php
	/*
	if ($a["x"] == $b["x"])
	{
		if ($a["y"] == $b["y"])
		{
			return 0;
		}
		elseif ($a["y"] > $b["y"])
		{
			return 1;
		}
		elseif ($a["y"] < $b["y"])
		{
			return -1;
		}
	}
	elseif ($a["x"] > $b["x"])
	{
		return 1;
	}
	elseif ($a["x"] < $b["x"])
	{
		return -1;
	}
	*/
	
	// Attempt #4: order by shortest distance to the target?
	if ($a["distance"] == $b["distance"])
		return 0;
	
	return ($a["distance"] < $b["distance"]) ? 1 : -1;
}
?>